module sdramddr2_controller (

    input         clk,              //SDRAM控制器时钟，100MHz
    input         sdram_clk_trans,
    input         rst_n,            //系统复位信号，低电平有效

    // FPGA与SDRAM硬件接口
    output [1    - 1 : 0] cmd_gen_chipsel, // CFG_MEM_IF_CS_WIDTH
    output [3    - 1 : 0] cmd_gen_bank, // CFG_MEM_IF_BA_WIDTH
    output [14   - 1 : 0] cmd_gen_row, // CFG_MEM_IF_ROW_WIDTH
    output reg [10   - 1 : 0] cmd_gen_col, // CFG_MEM_IF_COL_WIDTH
    output reg do_refresh,
    output     my_do_activate,
    output reg my_do_write,
    output reg my_do_read,
    output reg my_do_auto_precharge,
    output reg my_do_precharge,
    input [31:0] dio_rdata,
    input [63:0] dio_rdata64,
`ifdef USE_HALF_DDR
    output     [  7: 0] afi_dm,
    output     [ 63: 0] afi_wdata,
`else
    output reg [  7: 0] afi_dm,
    output reg [ 63: 0] afi_wdata,
`endif
    output              afi_dqs_burst,
    output              afi_wdata_valid,
    input local_init_done,


    
    output        idle,
    //SDRAM 控制器写端口  
    input         sdram_rw_req,     //读SDRAM请求信号
    output reg    sdram_rw_ack,
    input         sdram_read_or_write,     //写SDRAM请求信号
    input  [26:0] sdram_rw_addr,    //SDRAM地址  512M byte = 128M dword , align to 16byte
    input  [ 8:0] sdram_rw_burst,   //写sdram时数据突发长度
    input  [31:0] sdram_din,        //写入SDRAM的数据
    output [31:0] sdram_dout,       //从SDRAM读出的数据
    input  [ 3:0] sdram_mask,

    output reg enableRecorder,
    
    input block_auto_refresh
    
    );
localparam CFG_MEM_IF_CS_WIDTH = 1;
localparam CFG_MEM_IF_BA_WIDTH = 3;
localparam CFG_MEM_IF_ROW_WIDTH = 14;
localparam CFG_MEM_IF_COL_WIDTH = 10;

//localparam T1 = 1;//数据1
//localparam T2 = 5;//数据2

//1 trans = 16byte
//localparam TRANS_COUNT          = 2;//32 byte
//localparam TRANS_ADDR_WIDTH     = 1;
//localparam TRANS_COUNT          = 4;//64 byte
//localparam TRANS_ADDR_WIDTH     = 2;
//localparam TRANS_COUNT          = 8;//128 byte
//localparam TRANS_ADDR_WIDTH     = 3;
//localparam TRANS_COUNT          = 16;//256 byte
//localparam TRANS_ADDR_WIDTH     = 4;
//localparam TRANS_COUNT          = 32;//512 byte
//localparam TRANS_ADDR_WIDTH     = 5;
localparam TRANS_COUNT          = 64;//1024 byte
localparam TRANS_ADDR_WIDTH     = 6;

localparam DDR2_IDLE          = 0;
localparam DDR2_A             = 2;
localparam DDR2_B             = 3;
localparam DDR2_E             = 4;
localparam DDR2_F             = 5;
localparam DDR2_G             = 6;
localparam DDR2_REFRESH       = 7;

`ifdef USE_HALF_DDR
  wire [25:0] local_address = {sdram_rw_addr[26:0]};
`else
  wire [25:0] local_address = {sdram_rw_addr[26:2], 1'b0};
`endif
reg [9:0] refresh_cnt;
reg refresh_req;
reg refresh_ack;
reg [3:0] refresh_cntdown;
reg refresh_cntdown_finish1;
reg refresh_cntdown_finish2;

reg [3:0] ddr2_timer;


wire [CFG_MEM_IF_BA_WIDTH    - 1 : 0] bank;
wire [CFG_MEM_IF_ROW_WIDTH   - 1 : 0] row;
wire [CFG_MEM_IF_COL_WIDTH   - 1 : 0] col;

// assign bank = local_address[CFG_MEM_IF_BA_WIDTH - 1 - 1 + CFG_MEM_IF_ROW_WIDTH + CFG_MEM_IF_COL_WIDTH : CFG_MEM_IF_ROW_WIDTH - 1 + CFG_MEM_IF_COL_WIDTH];
// assign row  = local_address[CFG_MEM_IF_ROW_WIDTH - 1 - 1 + CFG_MEM_IF_COL_WIDTH : CFG_MEM_IF_COL_WIDTH - 1];
// assign col  = {local_address[CFG_MEM_IF_COL_WIDTH - 1 - 1 : 0], 1'b0};
assign {bank, row, col} = {local_address[CFG_MEM_IF_BA_WIDTH - 1 - 1 + CFG_MEM_IF_ROW_WIDTH + CFG_MEM_IF_COL_WIDTH : 0], 1'b0};

assign cmd_gen_bank = bank; // CFG_MEM_IF_BA_WIDTH
assign cmd_gen_row = row; // CFG_MEM_IF_ROW_WIDTH


assign cmd_gen_chipsel = 0;

assign idle = status == DDR2_IDLE;

assign afi_dqs_burst = trans_enable || trans_enable_dly;//trans_enable;
assign afi_wdata_valid = trans_enable || trans_enable_dly;//trans_enable;

reg [TRANS_ADDR_WIDTH+2 -1:0] ddr2_trans_count;
reg [TRANS_ADDR_WIDTH+2 -1:0] trans_count;//trans_status
reg trans_enable;
reg [1:0] ddr2_dly;

reg trans_count_2x;

`ifdef USE_dio_rdata64
assign sdram_dout = dio_rdata_temp;
`else
assign sdram_dout = dio_rdata;//sdram_clk_trans
`endif


`ifdef USE_HALF_DDR
  assign {afi_dm[7:6], afi_dm[3:2]} = sdram_mask;
  assign {afi_wdata[63:48], afi_wdata[31:16]} = sdram_din;
  assign {afi_dm[5:4], afi_dm[1:0]} = sdram_mask;
  assign {afi_wdata[47:32], afi_wdata[15:0]} = sdram_din;
  reg [31:0] dio_rdata_temp;
  always @(posedge sdram_clk_trans or negedge rst_n) begin
    dio_rdata_temp <= {dio_rdata64[15:0], dio_rdata64[47:32]};
  end
`else
  reg [31:0] dio_rdata_temp;
  always @(posedge sdram_clk_trans or negedge rst_n) begin
    if (!rst_n) begin
      trans_count_2x <= 0;
    end else begin

  `ifdef USE_dio_rdata64
      if(trans_count_2x==0)begin
        {afi_dm[7:6], afi_dm[3:2]} <= sdram_mask;
        {afi_wdata[63:48], afi_wdata[31:16]} <= sdram_din;
        dio_rdata_temp <= {dio_rdata64[31:16], dio_rdata64[63:48]};
      end else begin
        {afi_dm[5:4], afi_dm[1:0]} <= sdram_mask;
        {afi_wdata[47:32], afi_wdata[15:0]} <= sdram_din;
        dio_rdata_temp <= {dio_rdata64[15:0], dio_rdata64[47:32]};
      end
  `else
      if(trans_count_2x==0)begin
        afi_dm[7:4] <= sdram_mask;
        afi_wdata[63:32] <= sdram_din;
        dio_rdata_temp <= dio_rdata64[31:0];
      end else begin
        afi_dm[3:0] <= sdram_mask;
        afi_wdata[31:0] <= sdram_din;
        dio_rdata_temp <= dio_rdata64[63:32];
      end
  `endif

      if(trans_enable)begin
        trans_count_2x <= ~trans_count_2x;
      end else begin
        trans_count_2x <= 0;
      end

    end
  end
`endif

assign my_do_activate = status == DDR2_IDLE && !refresh_req && sdram_rw_req;
//assign my_do_activate = status == 1 && ddr2_dly==2;

reg trans_enable_dly;

`ifdef USE_dio_rdata64
  localparam READ_TRANS_TIMING = 7;
  `ifdef USE_HALF_DDR
    localparam READ_RECEIVE_TIMING = 6;
  `else
    localparam READ_RECEIVE_TIMING = 7;
  `endif
`else
  localparam READ_TRANS_TIMING = 5;
  localparam READ_RECEIVE_TIMING = 5;
`endif

wire [TRANS_ADDR_WIDTH+2 -1:0] trans_top;
`ifdef USE_HALF_DDR
    assign trans_top = sdram_rw_burst[8:1];
`else
    assign trans_top = sdram_rw_burst[8:2];
`endif

reg [2:0] status;
always @(posedge clk or negedge rst_n) begin
  if (!rst_n) begin
    status <= 0;
    sdram_rw_ack <= 0;
    refresh_cnt <= 0;
    refresh_req <= 0;
    refresh_ack <= 0;
    refresh_cntdown <= 0;
    refresh_cntdown_finish1 <= 0;
    refresh_cntdown_finish2 <= 0;
    do_refresh <= 0;

    ddr2_timer <= 0;

    //my_do_activate <= 0;
    my_do_read <= 0;
    my_do_write <= 0;
    my_do_auto_precharge <= 0;
    my_do_precharge <= 0;

    cmd_gen_col <= 0;
    ddr2_trans_count <= 0;
    trans_count <= 0;
    trans_enable <= 0;
    ddr2_dly <= 0;
    //trans_top <= 0;
    
    enableRecorder <= 0;
    trans_enable_dly <= 0;
  end else begin
    trans_enable_dly <= trans_enable;

    if(refresh_cnt==1023)begin//975
      refresh_req <= 1;
    end else begin
      if(local_init_done)begin
        refresh_cnt <= refresh_cnt + 1'b1;
      end
    end

    if(refresh_ack)begin
      refresh_req <= 0;
      refresh_cnt <= 0;
    end

    refresh_cntdown_finish1 <= refresh_cntdown==5;//7.5ns
    refresh_cntdown_finish2 <= refresh_cntdown==15;//195ns
         
    
    refresh_ack <= 0;
    do_refresh <= 0;
    

    if(trans_enable)begin
      trans_count <= trans_count + 1'b1;

      if(trans_count == {trans_top, 1'b1})begin
        trans_enable <= 0;
      end
    end else begin
      if(!sdram_read_or_write)begin//影响计数器和传输
        if(ddr2_timer == READ_TRANS_TIMING)begin//read
          trans_enable <= 1;
        end
      end else begin
        if(ddr2_timer == 3)begin//write
          trans_enable <= 1;
        end
      end
    end
    
    sdram_rw_ack <= 0;
    if(!sdram_read_or_write)begin//影响接收时序
      if(ddr2_timer == READ_RECEIVE_TIMING)begin//read
        sdram_rw_ack <= 1;
      end
    end else begin
      if(ddr2_timer == 2)begin
        sdram_rw_ack <= 1;
      end
    end

    //my_do_activate <= 0;
    my_do_read <= 0;
    my_do_write <= 0;
    my_do_auto_precharge <= 0;
    my_do_precharge <= 0;
    case(status)
    DDR2_IDLE: begin
      ddr2_trans_count <= 0;
  // `ifdef USE_HALF_DDR
  //     trans_top = sdram_rw_burst[8:1];
  // `else
  //     trans_top = sdram_rw_burst[8:2];
  // `endif
      refresh_cntdown <= 0;
      ddr2_timer <= 0;
      ddr2_dly <= 0;
      trans_count <= 0;
      trans_enable <= 0;
      enableRecorder <= 0;
      cmd_gen_col <= col;
      if(refresh_req)begin
        status <= DDR2_REFRESH;
      end else if(sdram_rw_req)begin
        //my_do_activate <= 1;
        status <= DDR2_A;//1
      end
    end

    // 1: begin
    //   ddr2_dly <= ddr2_dly + 1'b1;
    //   if(ddr2_dly==3)begin
    //       status <= DDR2_A;
    //   end
    // end

    DDR2_A: begin
      my_do_read <= !sdram_read_or_write;
      my_do_write <= sdram_read_or_write;
      ddr2_trans_count <= ddr2_trans_count + 1'b1;
      status <= DDR2_B;
      if(ddr2_trans_count == trans_top)begin
        //my_do_auto_precharge <= 1;
        status <= DDR2_E;
      end
      ddr2_timer <= ddr2_timer + 1'b1;
    end
    DDR2_B: begin
      cmd_gen_col <= cmd_gen_col + 4;
      ddr2_timer <= ddr2_timer + 1'b1;
      status <= DDR2_A;
    end

    DDR2_E: begin
      ddr2_timer <= ddr2_timer + 1'b1;
      if(trans_enable)begin
        status <= DDR2_F;
      end
    end

    DDR2_F: begin
      if(!trans_enable)begin
        my_do_precharge <= 1;
        if(!sdram_read_or_write)begin
          status <= DDR2_IDLE;
        end else begin
          status <= DDR2_G;
        end
      end
    end

    DDR2_G: begin
      ddr2_dly <= ddr2_dly + 1'b1;
      if(ddr2_dly==2)begin
          status <= DDR2_IDLE;
      end
    end

    //--------------------------------------------------------------------
    DDR2_REFRESH: begin
      refresh_cntdown <= refresh_cntdown + 1'b1;
      if(refresh_cntdown_finish1)begin
        do_refresh <= 1;
      end
      if(refresh_cntdown_finish2)begin
        refresh_ack <= 1;
        status <= DDR2_IDLE;
      end
    end


    endcase


  end
end


endmodule 